package com.shenglaotuan.community.article.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.shenglaotuan.community.article.entity.Article;
import com.shenglaotuan.community.article.entity.ArticleSimpleVO;
import com.shenglaotuan.community.article.entity.ArticleVO;
import com.shenglaotuan.community.article.mapper.ArticleMapper;
import com.shenglaotuan.community.article.service.ArticleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shenglaotuan.community.article_tag.entity.ArticleTag;
import com.shenglaotuan.community.article_tag.service.ArticleTagService;
import com.shenglaotuan.community.common.utils.FileUtils;
import com.shenglaotuan.community.tag.mapper.TagMapper;
import com.shenglaotuan.community.tag.service.TagService;
import com.shenglaotuan.community.tag.service.impl.TagServiceImpl;
import com.shenglaotuan.community.user.entity.User;
import com.shenglaotuan.community.user.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author ruidong
 * @since 2020-08-22
 */
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements ArticleService {

    @Autowired
    private ArticleTagService articleTagService;

    @Autowired
    private TagMapper tagMapper;

    @Autowired
    private UserService userService;

    @Value("${article.img.mark}")
    private String imgMark;
    @Value("${article.img.regex.content}")
    private String contentRegexTemplate;
    @Value("${article.img.regex.contentHtml}")
    private String contentHtmlRegexTemplate;
    @Value("${article.img.replace}")
    private String imgReplace;

    @Override
    @Transactional
    public void saveArticle(String uid, Article article, String[] tags, String host) {
        article.setUid(uid);
        // 标记图片
        markArticleImg(article, host, imgMark, 2);
        // 若文章id存在，则查询文章
        Article existArticle = null;
        if(StringUtils.isNotBlank(article.getId())){
            existArticle = getById(article.getId());
        }
        if(existArticle == null){
            // 文章不存在
            // 保存文章
            save(article);
        }else{
            // 文章存在
            // 保存文章
            existArticle.setContent(article.getContent());
            existArticle.setContentHtml(article.getContentHtml());
            save(existArticle);
            // 删除原标签
            articleTagService.remove(new QueryWrapper<ArticleTag>().eq("aid", existArticle.getId()));
        }
        if(tags != null && tags.length > 0){
            // 保存标签
            List<ArticleTag> articleTags = Arrays.stream(tags).map(tag -> new ArticleTag(tag, article.getId())).collect(Collectors.toList());
            articleTagService.saveBatch(articleTags);
        }
    }

    @Override
    public Integer countTotal(String uid, String query) {
        // uid为null时或者为"0"时，查询全文
        if("0".equals(uid) || StringUtils.isBlank(uid)){
            return count();
        }
        QueryWrapper<Article> queryWrapper = new QueryWrapper<Article>().eq("uid", uid);
        if ("1".equals(uid) && StringUtils.isNotBlank(query)) {
            queryWrapper = new QueryWrapper<Article>().like("title", query);
        }
        return count(queryWrapper);
    }

    @Override
    public List<ArticleSimpleVO> listSimple(String uid, Integer page, Integer record, String query) {
        List<Article> articles = new ArrayList<>();
        // 不传uid或者uid为"0"时，查询所有文章
        if("0".equals(uid) || "1".equals(uid) || StringUtils.isBlank(uid)){
            // 获取文章id
            if ("0".equals(uid) || StringUtils.isBlank(uid)){
                articles = page(new Page<>(page, record), new QueryWrapper<Article>().select("id").orderByDesc("gmt_created")).getRecords();
            } else {
                if (StringUtils.isNotBlank(query)) {
                    articles = page(new Page<>(page, record), new QueryWrapper<Article>().select("id").like("title", query).orderByDesc("gmt_created")).getRecords();
                }
            }

        }else{
            // 获取文章id
            articles = page(new Page<>(page, record), new QueryWrapper<Article>().eq("uid", uid).select("id").orderByDesc("gmt_created")).getRecords();
        }
        if(articles.isEmpty()){
            return new ArrayList<ArticleSimpleVO>();
        }
        List<ArticleSimpleVO> result = getBaseMapper().findSimpleArticle(articles);
        result.stream().forEach(articleSimpleVO -> articleSimpleVO.findTags(tagMapper));
        return result;
    }

    @Override
    public ArticleVO getArticle(String id, String host) {
        QueryWrapper<Article> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("id", "title", "content", "content_html", "gmt_created", "uid").eq("id", id);
        Article article = getOne(queryWrapper);
        markArticleImg(article, imgMark, host, 1);
        ArticleVO articleVO = new ArticleVO();
        // 复制属性
        BeanUtils.copyProperties(article, articleVO);
        // 获取文章对应的用户
        User user = userService.getInfo(article.getUid(), new String[]{"nickname"});
        user.setId(article.getUid());
        articleVO.setUser(user);
        articleVO.findTags(tagMapper);
        return articleVO;
    }

    @Override
    public void download(HttpServletResponse response, String id, String host) {
        try {
            Article article = getById(id);
            markArticleImg(article, imgMark, host, 1);

            FileUtils.setDownload(response, article.getTitle() + ".md");
            ServletOutputStream out = response.getOutputStream();
            out.write(article.getContent().getBytes());
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 标记图片，将文本中的图片域名替换为标记符
     * @param article 文章对象
     * @param replaceHost 服务器域名
     * @param replaceStr 被替换的文本
     * @param group 被替换组的下标
     */
    private void markArticleImg(Article article, String replaceHost, String replaceStr, int group) {
        StringBuffer content = new StringBuffer(article.getContent());
        StringBuffer contentHtml = new StringBuffer(article.getContentHtml());

        replaceHost = replaceHost.replaceAll("\\{", "\\\\{").replaceAll("\\}", "\\\\}");
        String contentRegex = contentRegexTemplate.replace(imgReplace, replaceHost);
        String contentHtmlRegex = contentHtmlRegexTemplate.replace(imgReplace, replaceHost);
        replaceImgMark(contentRegex, replaceStr, content, group);
        replaceImgMark(contentHtmlRegex, replaceStr, contentHtml, group);

        article.setContent(content.toString());
        article.setContentHtml(contentHtml.toString());
    }

    /**
     * 替换文本中的图片域名为标记
     * @param regex 正则字符串
     * @param replaceStr 替换的文本
     * @param content 被替换的文本
     * @param group 被替换组的下标
     */
    private void replaceImgMark(String regex, String replaceStr, StringBuffer content, int group) {
        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(content);
        int index = 0;
        int markLength = replaceStr.length();
        while (m.find(index)) {
            int start = m.start(group);
            int end = m.end(group);
            index = end - start + markLength;
            content.replace(start, end, replaceStr);
        }
    }
}
